/**
 * Copyright (c) 2010 deniskir@gmail.com. All rights reserved.
 *
 * @author Denis Kiriusin
 */

package com.dksoftware.combo;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.codec.digest.DigestUtils;

class HttpUtils {
	
	private HttpUtils() {
		// empty constructor
	}

    /**
     * Returns <tt>true</tt> if the request is conditional (i.e. "If-None-Match" header equals
     * "ETag" header), return <tt>false</tt> otherwise.
     *
     * @param request
     *            - HTTP request object to check
     * @param eTag
     *            - eTag string
     * @return <tt>true</tt> if the request is conditional and <tt>false</tt> otherwise.
     */
    static boolean isRequestModified(HttpServletRequest request, final String eTag) {
        final String ifNonMatch = HttpHeaders.IfNoneMatch.getName();
        if (request.getHeader(ifNonMatch) != null && eTag.equalsIgnoreCase(request.getHeader(ifNonMatch))) {
            return false;
        }
        return true;
    }

    /**
	 * Generates e-tag header ("8e0224303483a48d84b5db7fa4cf4b3e"),<br>
	 * <b>Note</b>: the ETag header must be wrapped with double quotes.
	 * 
	 * @return eTag string
	 */
	static String createEtag(String s) {
		return new StringBuilder(34).append("\"").append(DigestUtils.md5Hex(s)).append("\"").toString();
	}

    /**
     * Returns <tt>true</tt> if client accepts compressed content and <tt>false</tt> otherwise.
     *
     * @param request
     *            - HTTP request object
     * @return <tt>true</tt> - if compressed content accepted by client<br>
     *         <tt>false</tt> - if compressed content is not accepted by client
     */
    static boolean isCompressionAccepted(HttpServletRequest request) {
        boolean acceptCompress = false;

        final String acceptEncoding = HttpHeaders.AcceptEncoding.getName();

        if (request.getHeader(acceptEncoding) != null && request.getHeader(acceptEncoding).indexOf("gzip") != -1) {
            acceptCompress = true;
        } else if (request.getHeader("---------------") != null) {
            // Norton Internet Security
            // see http://tinymce.moxiecode.com/punbb/viewtopic.php?pid=6250#p6250
            acceptCompress = true;
        }
        // test for IE < 7.0
        if (isIE70orLess(request)) {
            acceptCompress = false;
        }

        return acceptCompress;
    }

    /**
     * Returns the servlet path of a request. Some servlet containers return various strange,
     * unhelpful values from {@link HttpServletRequest#getServletPath()}, so this function tries a
     * few methods to get the same information.
     *
     * @param request
     *            the {@link HttpServletRequest} to get the path information from.
     * @return the servlet path
     */
    static String getServletPath(HttpServletRequest request) {
        String thisPath = request.getServletPath();

        if (thisPath == null) {
            final String requestURI = request.getRequestURI();
            if (request.getPathInfo() != null) {
                // strip the pathInfo from the requestURI
                thisPath = requestURI.substring(0, requestURI.indexOf(request.getPathInfo()));
            } else {
                thisPath = requestURI;
            }
        } else if (thisPath.equals("") && request.getPathInfo() != null) {
            thisPath = request.getPathInfo();
        }

        return thisPath;
    }

    /**
     * Check to see if the current request is originating from an IE browser whose version is less
     * than version 7.0. If so, return true, else false.
     *
     * @param request
     *            - the current request
     * @return true if less than IE 7.0, true otherwise
     */
    static boolean isIE70orLess(HttpServletRequest request) throws NumberFormatException {
        // browser detection
        String userAgent = request.getHeader("User-Agent");

        if (userAgent == null || "".equalsIgnoreCase(userAgent))
            return false;

        userAgent = userAgent.toLowerCase();

        // gecko based browser
        if (userAgent.indexOf("msie") == -1) {
            return false;
        }
        // ie version 7.0 on windows is the lowest minimum we'll take
        else if (userAgent.indexOf("msie") != -1 && userAgent.indexOf("windows") != -1) {
            boolean sp2 = userAgent.indexOf("sv1;") != -1;

            // http://msdn.microsoft.com/workshop/author/dhtml/overview/aboutuseragent.asp
            int verStart = userAgent.indexOf("msie");
            int verEnd = userAgent.indexOf(";", verStart);

            // try to parse
            String rv = userAgent.substring(verStart + 5, verEnd);
            // strip out letters - always seem to be the last character (i.e. 1.4b, 1.5a)
            if (Character.isLetter(rv.charAt(rv.length() - 1))) {
                rv = rv.substring(0, rv.length() - 1);
            }

            double ver = Double.parseDouble(rv);
            return ver < 7 || (ver == 6 && !sp2);
        }
        return false;
    }
    
    /**
     * Most proxies, most notably Squid up through version 3.0, do not cache resources with a "?" in
     * their URL even if a Cache-control: public header is present in the response. To enable proxy
     * caching for these resources, remove query strings from references to static resources, and
     * instead encode the parameters into the file names themselves.
     *
     * @see http://code.google.com/speed/page-speed/docs/caching.html
     *
     * @param requestURL - the request URL
     * @return query string parameters unmodifiable Map, never null
     */
    static Map<String, String> getQueryStringParameters(final String requestURL) {
        final Map<String, String> paramMap = new HashMap<String, String>();
        if (requestURL == null) {
            return paramMap;
        }
        int i = 0;
        for (final String param : requestURL.split("&")) {
            if (i > 0) {
                String key = param.split("=")[0];
                String value = param.split("=")[1];
                paramMap.put(key, value);
            }
            i++;
        }
        return Collections.unmodifiableMap(paramMap);
    }

}
